package jmetal.problems;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;

import jmetal.core.Problem;
import jmetal.core.Solution;
import jmetal.core.Variable;
import jmetal.encodings.solutionType.IntSolutionType;
import jmetal.util.JMException;

@SuppressWarnings("serial")
public class MORAP extends Problem{

	private double[] cost ;
	private double[] probility;
	private double[] theta;
	private double[] weight;
	private double[] gamma;
	private int maxNumberOfCompo;
	private double maxWeight;
	
	public MORAP(String path, int numberOfSubSystem, int maxNumberOfCompo, int maxWeight){
		cost = new double [numberOfSubSystem];
		probility = new double[numberOfSubSystem];
		theta = new double [numberOfSubSystem];
		weight = new double [numberOfSubSystem];
		gamma = new double [numberOfSubSystem];
		this.maxNumberOfCompo = maxNumberOfCompo;
		this.maxWeight = maxWeight ;
		readProblem(path);
		numberOfVariables_ = numberOfSubSystem ;
		numberOfObjectives_ = 2;
		numberOfConstraints_ = 1;
	    lowerLimit_ = new double[numberOfVariables_];
	    upperLimit_ = new double[numberOfVariables_];  
	    for(int i = 0;i<numberOfVariables_;i++){
	    	lowerLimit_[i] = 1.0;
	    	upperLimit_[i] = this.maxNumberOfCompo;
	    }
	    solutionType_ = new IntSolutionType(this) ;
	}
	
	private void readProblem(String path) {
		try {
			List<String> allStrs = Files.readAllLines(Paths.get(path)) ;
			for(String str : allStrs){
				String[] strs = str.split("\\s+");
				if(strs[0].equals("c")){
					for(int i = 1;i<strs.length;i++){
						cost[i-1] = Double.parseDouble(strs[i]) ;
					}
				}else if(strs[0].equals("r")){
					for(int i = 1;i<strs.length;i++){
						probility[i-1] = Double.parseDouble(strs[i]) ;
					}					
				}else if(strs[0].equals("theta")){
					for(int i = 1;i<strs.length;i++){
						theta[i-1] = Double.parseDouble(strs[i]) ;
					}	
				}else if(strs[0].equals("w")){
					for(int i = 1;i<strs.length;i++){
						weight[i-1] = Double.parseDouble(strs[i]) ;
					}						
				}else if(strs[0].equals("gamma")){
					for(int i = 1;i<strs.length;i++){
						gamma[i-1] = Double.parseDouble(strs[i]) ;
					}					
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}

	@Override
	public void evaluate(Solution solution) throws JMException {
		Variable[] variables = solution.getDecisionVariables();
		double f1 = 1.0;
		double f2 = 0.0;
		for(int i = 0;i<variables.length;i++){
			double xi = variables[i].getValue() ;
			f1 *= (1 - Math.pow(1 - probility[i], xi)) ;
			f2 += cost[i] * (xi + Math.exp(0.25 * xi)) ;
		}
		solution.setObjective(0, -f1);
		solution.setObjective(1, f2);
		
	}
	
	@Override
	public void evaluateConstraints(Solution solution) throws JMException {
		
		double weightSum = 0;
		Variable[] variables = solution.getDecisionVariables();
		for(int i = 0;i<weight.length;i++){
			int a = (int) variables[i].getValue();
			weightSum += weight[i] * (a * Math.exp(a * 0.25)) ;
		}
		double constrain = weightSum - maxWeight ;
	    double total = 0.0;
	    int number = 0;
		if(constrain < 0){
			total = constrain ;
			number ++ ;
		}
		solution.setOverallConstraintViolation(total);
		solution.setNumberOfViolatedConstraint(number);
	}

}
